# Google command line interface
# Copyright (C) 2005 by Deryck Hodge
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


from SOAPpy import WSDL


class Service:
    """Load the GoogleSearch WSDL and initialize the connection."""

    def __init__(self, params):
        self.params = params
        # Hardcode the path for now
        # TODO: Fix this to be set at install
        self.connection = WSDL.Proxy('/etc/gcli/GoogleSearch.wsdl')


class Request(Service):
    """ Search requests always follow the form:

        doGoogleSearch(key, query, start_num, max_results, filter,
                       restrict, safe_search, lang_resrict, input_enc,
                       output_enc)
    """

    def __init__(self, params):
        Service.__init__(self, params) 
        self._results = self.connection.doGoogleSearch(self.params[0], 
                            self.params[1], self.params[2], self.params[3], 
                            self.params[4], self.params[5], self.params[6], 
                            self.params[7], self.params[8], self.params[9])

    def do_search(self):
        """ Results are returned as the complete result obj from Google. """
        return self._results


class Query:

    def __init__(self, params):
        """ Params should be passed in as a Params() object.
            Anytime the params are changed a new Request() object
            must be initialized. """

        self.key = params.key
        self.query = params.query
        self.index_start = params.index_start
        # Use max and qmax to distinquish the number the user wants from
        # the max of 10 allowed with each query.  Set qmax to max when
        # requesting less than 10 results.
        self.max_results = params.max_results
        if self.max_results < 10:
            self.qmax_results = self.max_results
        else:
            self.qmax_results = 10
        self.filter = params.filter
        self.restrictions = params.restrictions
        self.safe_search = params.safe_search
        self.language = params.language
        self.input_enc = params.input_enc 
        self.output_enc = params.output_enc

    def list_params(self):
        return (self.key, self.query, self.index_start, self.qmax_results, 
                    self.filter, self.restrictions, self.safe_search, 
                    self.language, self.input_enc, self.output_enc)

    def list_params_set(self):
        param_set = []
        max_results = self.max_results
        while max_results:
            if max_results < 10:
                param_set.append(self.list_params())
                max_results = 0
            else:
                param_set.append(self.list_params())
                if (max_results - 10) >= 10:
                    # Reduce the number until all results are run
                    max_results = max_results - 10
                    self.index_start = self.index_start + 10
                elif (max_results - 10) == 0:
                    max_results = 0 
                elif (max_results - 10) < 10:
                    self.index_start = self.index_start + 10
                    self.qmax_results = max_results - 10
                    param_set.append(self.list_params())
                    max_results = 0
        return param_set


class Search(Query):

    def __init__(self, params):
        Query.__init__(self, params)
        self.search_results = []

        # Use self.count to help gauge that there's enough results
        # to support the requested max number
        max = self.max_results
        if max > 10:
            pset = self.list_params_set()
            # Run the first set to get a results count
            results = Request(pset[0]).do_search()
            self.search_results.append(results)
            pset.pop(0)
            n = self.count()
            # Now check against count of available results
            if n < max and n > 10:
                while n:
                    results = Request(pset[0]).do_search()
                    self.search_results.append(results)
                    pset.pop(0)
                    if n >= 10:
                        n = n - 10
                    else:
                        n = 0
            elif n > max:
                for p in pset:
                    results = Request(p).do_search()
                    self.search_results.append(results)
        else:
            results = Request(self.list_params()).do_search()
            self.search_results.append(results)

    def response(self):
        """Return the entire search response."""
        response = []
        for result in self.search_results:
            response.append(result)
        return response

    def results(self):
        """ Search().results() returns a list of resultElements. """
        elements = []
        for result in self.search_results:
            elements.append(result.resultElements)
        return elements

    def count(self):
        if len(self.search_results) > 0:
            return self.search_results[0].estimatedTotalResultsCount
        else:
            return 0
